package com.hwn.datax.controller;

import cn.hutool.core.convert.Convert;
import cn.hutool.json.JSONUtil;
import com.hwn.datax.component.DynamicMenuTreeCell;
import com.hwn.datax.component.MenuItemData;
import com.hwn.datax.component.SpringFXMLLoader;
import com.hwn.datax.component.StatusDisplay;
import com.hwn.datax.domain.DataxJob;
import com.hwn.datax.domain.DataxJobGroup;
import com.hwn.datax.domain.DataxJobRunLog;
import com.hwn.datax.domain.TreeItemNode;
import com.hwn.datax.event.CustomSpringEvent;
import com.hwn.datax.service.ConfigService;
import com.hwn.datax.service.DataxJobGroupService;
import com.hwn.datax.service.DataxJobService;
import com.hwn.datax.utils.AlertUtil;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Insets;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import javafx.scene.transform.Scale;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.util.Callback;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Controller;

import java.io.IOException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

@Controller
public class JobRunController {

    @FXML
    public TableColumn<DataxJobRunLog, String> operationColumn;

    @FXML
    public TableColumn<DataxJobRunLog, String> startTimeColumn;
    @FXML
    public TableColumn<DataxJobRunLog, Long> totalRecordsColumn;

    @FXML
    private TableColumn<DataxJobRunLog, Integer> statusColumn;

    @FXML
    private TableColumn<DataxJobRunLog, Double> progressColumn;

    @FXML
    private TableColumn<DataxJobRunLog, String> jobName;

    @FXML
    TableView<DataxJobRunLog> tableView;

    @Autowired
    DataxJobService dataxJobService;

    @Autowired
    private DataxJobGroupService dataxJobGroupService;

    @FXML
    private TreeView<TreeItemNode> treeView;

    @FXML
    private Button addGroupBtn;
    @FXML
    public TextField searchGroupTx;

    @Autowired
    SpringFXMLLoader springFXMLLoader;

    @Autowired
    ConfigService configService;

    public void initialize() {

        loadDataxGroupTreeViewData();

        addGroupBtn.setOnAction(e -> {
            showDataxJobGroupEditDialog(new DataxJobGroup());
        });

        setOperationColumn();

        ObservableList<DataxJobRunLog> dataxJobRunLogList = dataxJobService.getDataxJobRunLogList();

        tableView.setItems(dataxJobRunLogList);

        jobName.setStyle("-fx-alignment: CENTER;");

        jobName.setCellValueFactory(new PropertyValueFactory<>("jobName"));

        totalRecordsColumn.setCellValueFactory(new PropertyValueFactory<>("totalRecords"));
        totalRecordsColumn.setStyle("-fx-alignment: CENTER_RIGHT;");
        startTimeColumn.setCellValueFactory(new PropertyValueFactory<>("startTime"));
        startTimeColumn.setStyle("-fx-alignment: CENTER;");


        setProgressColumn();
        progressColumn.setStyle("-fx-alignment: CENTER;");

        statusColumn.setCellValueFactory(cellData -> cellData.getValue().statusProperty().asObject());
        statusColumn.setCellFactory(new Callback<>() {
            @Override
            public TableCell<DataxJobRunLog, Integer> call(TableColumn<DataxJobRunLog, Integer> param) {
                return new TableCell<DataxJobRunLog, Integer>() {
                    @Override
                    protected void updateItem(Integer item, boolean empty) {
                        super.updateItem(item, empty);
                        if (empty || item == null) {
                            setGraphic(null);
                        } else {
                            StackPane stackPane = new StackPane();
                            stackPane.setPrefSize(16, 16);
                            StatusDisplay statusDisplay = new StatusDisplay();
                            String status = item == 0 ? "loading" : item == 1 ? "success" : "error";
                            statusDisplay.statusProperty().set(status);
                            // 创建Scale变换对象
                            Scale scaleTransform = new Scale();
                            scaleTransform.setX(0.4); // 缩放比例
                            scaleTransform.setY(0.4);
                            scaleTransform.setPivotX(18); // 设定缩放原点为左上角
                            scaleTransform.setPivotY(4);
                            // 将Scale变换添加到SVGPath
                            statusDisplay.getTransforms().add(scaleTransform);
                            stackPane.getChildren().add(statusDisplay);
                            setGraphic(stackPane);
                        }
                    }
                };
            }
        });
        statusColumn.setStyle("-fx-alignment: CENTER;");
        // 动态设置列宽
        progressColumn.prefWidthProperty().bind(tableView.widthProperty().multiply(0.32));
        jobName.prefWidthProperty().bind(tableView.widthProperty().multiply(0.2));
        operationColumn.prefWidthProperty().bind(tableView.widthProperty().multiply(0.16));
        operationColumn.setMaxWidth(140);
        statusColumn.prefWidthProperty().bind(tableView.widthProperty().multiply(0.06));
        statusColumn.setMaxWidth(60);
        startTimeColumn.setPrefWidth(150);
    }


    private void setProgressColumn() {
        progressColumn.setCellValueFactory(cellData -> cellData.getValue().percentageProperty().divide(100).asObject());
        progressColumn.setCellFactory(new Callback<>() {
            @Override
            public TableCell<DataxJobRunLog, Double> call(TableColumn<DataxJobRunLog, Double> param) {
                return new TableCell<DataxJobRunLog, Double>() {
                    private final ProgressBar progressBar = new ProgressBar();

                    private final Label label = new Label();

                    private ChangeListener<Number> changeListener;

                    {
                        progressBar.setMaxWidth(Double.MAX_VALUE);
                        progressBar.setPrefSize(180, 14);
                        label.setMinWidth(46);
                        progressBar.getStyleClass().addAll("bar", "track", "progress-bar-blue");
                    }

                    private void setProgressBarClass(int status) {
                        // 首先移除所有相关的样式类
                        progressBar.getStyleClass().removeAll("progress-bar-blue", "progress-bar-green", "progress-bar-red");
                        switch (status) {
                            case 0 -> progressBar.getStyleClass().add("progress-bar-blue");
                            case 1 -> progressBar.getStyleClass().add("progress-bar-green");
                            case 2 -> {
                                progressBar.getStyleClass().add("progress-bar-red");
                                if (progressBar.getProgress() < 0) progressBar.setProgress(0);
                            }
                        }
                    }

                    @Override
                    protected void updateItem(Double item, boolean empty) {
                        super.updateItem(item, empty);
                        if (changeListener != null) {
                            getTableRow().getItem().statusProperty().removeListener(changeListener);
                            progressBar.setProgress(-1);
                        }
                        if (empty || item == null) {
                            setGraphic(null);
                        } else {
                            DataxJobRunLog dataxJobRunLog = getTableRow().getItem();
                            if (dataxJobRunLog != null) {
                                setProgressBarClass(dataxJobRunLog.getStatus());
                                dataxJobRunLog.statusProperty().addListener((observable, oldValue, newValue) -> {
                                    setProgressBarClass(newValue.intValue());
                                });
                            }
                            if (item > 0) {
                                progressBar.setProgress(item);
                            }
                            DecimalFormat df = new DecimalFormat("0.##");
                            String formattedText = df.format(item * 100) + "%";
                            label.setText(formattedText);
                            HBox hBox = new HBox(progressBar, label);
                            hBox.setPrefWidth(getTableColumn().getWidth());
                            HBox.setHgrow(progressBar, Priority.ALWAYS);
                            hBox.setSpacing(4);
                            hBox.setPadding(new Insets(4, 4, 0, 4));
                            setGraphic(hBox);
                        }
                    }
                };
            }
        });
    }

    private void setOperationColumn() {
        operationColumn.setCellValueFactory(new PropertyValueFactory<>("uuid"));
        operationColumn.setCellFactory(new Callback<TableColumn<DataxJobRunLog, String>, TableCell<DataxJobRunLog, String>>() {
            @Override
            public TableCell<DataxJobRunLog, String> call(TableColumn<DataxJobRunLog, String> param) {
                return new TableCell<DataxJobRunLog, String>() {
                    private final Button lookBtn = new Button("详情");
                    private final Button cancelBtn = new Button("停止");

                    private final Button removeBtn = new Button("删除");

                    private ChangeListener<Number> changeListener;

                    {
                        lookBtn.setOnAction(e -> {
                            FXMLLoader loader = springFXMLLoader.getLoader("views/job-run-log.fxml");
                            Parent root = null;
                            try {
                                root = loader.load();
                            } catch (IOException ex) {
                                throw new RuntimeException(ex);
                            }
                            JobRunLogController controller = loader.getController();
                            controller.setUuid(getItem());
                            Stage stage = new Stage();
                            stage.setTitle("任务运行情况");
                            stage.setScene(new Scene(root));
                            // Make the popup modal
                            stage.initModality(Modality.APPLICATION_MODAL);
                            Platform.runLater(stage::showAndWait);

                        });
                        cancelBtn.setOnAction(e -> {
                            dataxJobService.killDataxJob(getItem());
                        });
                        removeBtn.setOnAction(e -> {
                            Platform.runLater(() -> {
                                dataxJobService.removeExecKeys(Collections.singletonList(getItem()));
                                DataxJobRunLog jobRunLog = getTableRow().getItem();
                                jobRunLog.statusProperty().removeAllMyListeners();
                                tableView.refresh();
                            });
                        });
                    }

                    @Override
                    protected void updateItem(String item, boolean empty) {
                        super.updateItem(item, empty);
                        if (empty || item == null) {
                            setGraphic(null);
                        } else {
                            HBox hBox = new HBox();
                            DataxJobRunLog jobRunLog = getTableRow().getItem();
                            if (jobRunLog == null) {
                                setGraphic(null);
                                return;
                            }
                            hBox.getChildren().add(lookBtn);
                            hBox.getChildren().add(cancelBtn);
                            if (changeListener == null) {
                                changeListener = (observable, oldValue, newValue) -> {
                                    if (newValue != null && newValue.intValue() != 0) {
                                        hBox.getChildren().remove(cancelBtn);
                                        hBox.getChildren().add(removeBtn);
                                    }
                                };
                                jobRunLog.statusProperty().addListener(changeListener);
                            }
                            if (jobRunLog.statusProperty().get() != 0) {
                                hBox.getChildren().remove(cancelBtn);
                                hBox.getChildren().add(removeBtn);
                            }
                            hBox.setSpacing(6);
                            setGraphic(hBox);
                        }
                    }
                };
            }
        });
    }

    private void loadDataxGroupTreeViewData() {
        // 初始化树形菜单
        TreeItem<TreeItemNode> rootItem = new TreeItem<>();
        rootItem.setExpanded(true);
        List<DataxJobGroup> list = dataxJobGroupService.list();

        list.forEach(t -> {
            TreeItem<TreeItemNode> treeItem = new TreeItem<>(new TreeItemNode<DataxJobGroup>(t.getGroupName(), t));
            List<DataxJob> dataxJobs = dataxJobService.listByGroupId(t.getId());
            // 添加子节点
            dataxJobs.forEach(t1 -> {
                TreeItem<TreeItemNode> childTreeItem = new TreeItem<>(new TreeItemNode<DataxJob>(t1.getJobName(), t1));
                treeItem.getChildren().add(childTreeItem);
            });
            rootItem.getChildren().add(treeItem);
        });

        treeView.setRoot(rootItem);
        List<MenuItemData<TreeItemNode>> menuItemsData = new ArrayList<>();
        // 添加菜单项和对应的动作
        menuItemsData.add(new MenuItemData<>("编辑", item -> {
            DataxJob value = (DataxJob) item.getValue();
            FXMLLoader load = springFXMLLoader.getLoader("views/job-edit.fxml");
            Parent root;
            try {
                root = load.load();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            JobEditController jobEditController = load.getController();
            jobEditController.setDataxJob(value);
            Stage stage = new Stage();
            stage.setTitle("编辑任务");
            stage.setScene(new Scene(root));
            // Make the popup modal
            stage.initModality(Modality.APPLICATION_MODAL);
            // Show the popup and wait until it is closed
            stage.showAndWait();
        }, item -> item != null && item.getValue() instanceof DataxJob));
        menuItemsData.add(new MenuItemData<>("执行", item -> dataxJobService.executeDataxJob(((DataxJob) item.getValue()).getId()), item -> item != null && item.getValue() instanceof DataxJob));
        menuItemsData.add(new MenuItemData<>("区间执行", item -> {
            Platform.runLater(() -> {
                Dialog<String> dialog = new Dialog<>();
                dialog.setTitle("区间设置");
                dialog.setHeaderText("请输入区间设置");
                FXMLLoader loader = springFXMLLoader.getLoader("views/range-option.fxml");
                Parent root = null;
                try {
                    root = loader.load();
                } catch (IOException ex) {
                    throw new RuntimeException(ex);
                }
                RunRangeOptionController controller = loader.getController();
                DataxJob job = (DataxJob) item.getValue();
                controller.setRangeOption(job.getRangeOption(), result -> {
                    Platform.runLater(() -> {
                        job.setRangeOption(result);
                        dataxJobService.save(job);
                        dataxJobService.executeDataxJobByRange(job.getId());
                    });
                });
                // 显示弹窗
                Stage dialogStage = new Stage();
                dialogStage.initModality(Modality.APPLICATION_MODAL);
                dialogStage.setScene(new Scene(root));
                dialogStage.showAndWait();
            });
        }, item -> item != null && item.getValue() instanceof DataxJob));
        menuItemsData.add(new MenuItemData<>("删除", item -> {
            Platform.runLater(() -> {
                DataxJob job = (DataxJob) item.getValue();
                dataxJobService.remove(job.getId());
                AlertUtil.showSuccessAlert("删除任务成功" + job.getJobName());
                loadDataxGroupTreeViewData();
            });
        }, item -> item != null && item.getValue() instanceof DataxJob));

        menuItemsData.add(new MenuItemData<>("编辑名称", item -> {
            DataxJobGroup value = (DataxJobGroup) item.getValue();
            showDataxJobGroupEditDialog(value);
        }, item -> item != null && !(item.getValue() instanceof DataxJob)));
        menuItemsData.add(new MenuItemData<>("添加任务", item -> {
            DataxJobGroup group = (DataxJobGroup) item.getValue();
            DataxJob dataxJob = JSONUtil.toBean(configService.getConfig("DefaultDataxTemplate"), DataxJob.class);
            dataxJob.setGroupId(group.getId());
            FXMLLoader load = springFXMLLoader.getLoader("views/job-edit.fxml");
            Parent root;
            try {
                root = load.load();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            JobEditController jobEditController = load.getController();
            jobEditController.setDataxJob(dataxJob);
            Stage stage = new Stage();
            stage.setTitle("添加任务");
            stage.setScene(new Scene(root));
            stage.initModality(Modality.APPLICATION_MODAL);
            // Show the popup and wait until it is closed
            stage.showAndWait();
        }, item -> item != null && !(item.getValue() instanceof DataxJob)));
        menuItemsData.add(new MenuItemData<>("批量添加任务", item -> {
            DataxJobGroup value = (DataxJobGroup) item.getValue();
            Parent load = springFXMLLoader.load("views/job-batch-create.fxml");
            Stage stage = new Stage();
            stage.setTitle("批量添加任务");
            stage.setScene(new Scene(load));
            // Make the popup modal
            stage.initModality(Modality.APPLICATION_MODAL);
            // Show the popup and wait until it is closed
            stage.showAndWait();
        }, item -> item != null && !(item.getValue() instanceof DataxJob)));
        menuItemsData.add(new MenuItemData<>("批量执行", item -> {
            DataxJobGroup value = (DataxJobGroup) item.getValue();
            List<DataxJob> dataxJobs = dataxJobService.listByGroupId(value.getId());
            Platform.runLater(() -> {
                dataxJobs.forEach(t -> dataxJobService.executeDataxJob(t.getId()));
            });
        }, item -> item != null && !(item.getValue() instanceof DataxJob)));

        treeView.setCellFactory(tv -> new DynamicMenuTreeCell<>(menuItemsData));

        // 隐藏虚拟根节点
        treeView.setShowRoot(false);

        // 添加点击事件监听器
        treeView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
            if (newValue != null && newValue.getValue() != null) {

            }
        });
    }

    @EventListener
    public void onApplicationEvent(CustomSpringEvent event) {
        String message = event.getMessage();
        ObservableList<TreeItem<TreeItemNode>> children = treeView.getRoot().getChildren();
        children.stream().forEach(item -> {
            DataxJobGroup group = (DataxJobGroup) item.getValue().getValue();
            if (Convert.toStr(group.getId()).equals(message)) {
                item.getChildren().clear();
                List<DataxJob> dataxJobs = dataxJobService.listByGroupId(group.getId());
                // 添加子节点
                dataxJobs.forEach(t1 -> {
                    TreeItem<TreeItemNode> childTreeItem = new TreeItem<>(new TreeItemNode<DataxJob>(t1.getJobName(), t1));
                    item.getChildren().add(childTreeItem);
                });
                //展开节点
                item.setExpanded(true);
            }
        });
    }


    private void showDataxJobGroupEditDialog(DataxJobGroup dataxJobGroup) {
        Dialog<String> dialog = new Dialog<>();
        dialog.setTitle("编辑Datax作业组");
        dialog.setHeaderText("请输入作业组名称");

        // 创建一个文本输入框
        TextField nameField = new TextField();
        nameField.setText(dataxJobGroup.getGroupName());

        // 创建一个确认按钮和一个取消按钮
        ButtonType okButtonType = new ButtonType("确定", ButtonBar.ButtonData.OK_DONE);
        ButtonType cancelButtonType = new ButtonType("取消", ButtonBar.ButtonData.CANCEL_CLOSE);
        dialog.getDialogPane().setPadding(new Insets(20, 20, 20, 20));
        dialog.getDialogPane().getButtonTypes().addAll(okButtonType, cancelButtonType);
        dialog.getDialogPane().setContent(nameField);
        dialog.setResultConverter(dialogButton -> {
            if (dialogButton == okButtonType) {
                return nameField.getText();
            }
            return null;
        });
        Optional<String> result = dialog.showAndWait();
        result.ifPresent(t -> {
            dataxJobGroup.setGroupName(t);
            dataxJobGroupService.save(dataxJobGroup);
            loadDataxGroupTreeViewData();
        });

    }
}